//#include <opencv/cv.h>
//#include <opencv2/core/core.hpp>
//#include <opencv2/highgui/highgui.hpp>
//#include <iostream>

//using namespace cv;
//using namespace std;

/*int main( int argc, char** argv )
{
	if( argc != 2)
	{
		cout <<" Usage: display_image ImageToLoadAndDisplay" << endl;
		return -1;
	}

	Mat image;
	image = imread(argv[1], CV_LOAD_IMAGE_COLOR);   // Read the file

	if(! image.data )                              // Check for invalid input
	{
		cout <<  "Could not open or find the image" << std::endl ;
		return -1;
	}

	namedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.
	imshow( "Display window", image );                   // Show our image inside it.

	waitKey(0);                                          // Wait for a keystroke in the window
	return 0;
}*/


/*const int MAX_CORNERS = 500;

int main(int argc, char* argv[])
{
	// Load two images and allocate other structures
	IplImage* imgA = cvLoadImage("CapTest2-00000-00003.pgm", CV_LOAD_IMAGE_COLOR);
	IplImage* imgB = cvLoadImage("CapTest2-00001-00003.pgm", CV_LOAD_IMAGE_COLOR);

	CvSize img_sz = cvGetSize( imgA );
	int win_size = 15;

	IplImage* imgC = cvLoadImage("OpticalFlow1.png", CV_LOAD_IMAGE_UNCHANGED);

	// Get the features for tracking
	//IplImage* eig_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );
	//IplImage* tmp_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );

	int corner_count = MAX_CORNERS;
	CvPoint2D32f* cornersA = new CvPoint2D32f[ MAX_CORNERS ];

	cvGoodFeaturesToTrack( imgA, NULL, NULL, cornersA, &corner_count,
		0.05, 5.0, 0, 3, 0, 0.04 );

	cvFindCornerSubPix( imgA, cornersA, corner_count, cvSize( win_size, win_size ),
		cvSize( -1, -1 ), cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03 ) );

	// Call Lucas Kanade algorithm
	char features_found[ MAX_CORNERS ];
	float feature_errors[ MAX_CORNERS ];

	CvSize pyr_sz = cvSize( imgA->width+8, imgB->height/3 );

	IplImage* pyrA = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );
	IplImage* pyrB = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );

	CvPoint2D32f* cornersB = new CvPoint2D32f[ MAX_CORNERS ];

	cvCalcOpticalFlowPyrLK( imgA, imgB, pyrA, pyrB, cornersA, cornersB, corner_count, 
		cvSize( win_size, win_size ), 5, features_found, feature_errors,
		cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.3 ), 0 );

	// Make an image of the results
	for( int i=0; i < 550; i++ ){

		//printf("Error is %f/n", feature_errors[i]);
		//continue;

		printf("Got it/n");
		CvPoint p0 = cvPoint( cvRound( cornersA[i].x ), cvRound( cornersA[i].y ) );
		CvPoint p1 = cvPoint( cvRound( cornersB[i].x ), cvRound( cornersB[i].y ) );
		cvLine( imgC, p0, p1, CV_RGB(255,0,0), 2 );
}

cvNamedWindow( "ImageA", 0 );
cvNamedWindow( "ImageB", 0 );
cvNamedWindow( "LKpyr_OpticalFlow", 0 );

cvShowImage( "ImageA", imgA );
cvShowImage( "ImageB", imgB );
cvShowImage( "LKpyr_OpticalFlow", imgC );

cvWaitKey(0);

return 0;
}*/

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"

using namespace cv;

void readme();

/** @function main */
/*int main( int argc, char** argv )
{
	//if( argc != 3 )
	//{ readme(); return -1; }

	Mat img_object = imread( "CapTest2-00000-00003.pgm", CV_LOAD_IMAGE_COLOR );
	Mat img_scene = imread("CapTest2-00001-00003.pgm", CV_LOAD_IMAGE_COLOR );

	if( !img_object.data || !img_scene.data )
	{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }

	//-- Step 1: Detect the keypoints using SURF Detector
	int minHessian = 400;

	SurfFeatureDetector detector( minHessian );

	std::vector<KeyPoint> keypoints_object, keypoints_scene;

	detector.detect( img_object, keypoints_object );
	detector.detect( img_scene, keypoints_scene );

	//-- Step 2: Calculate descriptors (feature vectors)
	SurfDescriptorExtractor extractor;

	Mat descriptors_object, descriptors_scene;

	extractor.compute( img_object, keypoints_object, descriptors_object );
	extractor.compute( img_scene, keypoints_scene, descriptors_scene );

	//-- Step 3: Matching descriptor vectors using FLANN matcher
	FlannBasedMatcher matcher;
	std::vector< DMatch > matches;
	matcher.match( descriptors_object, descriptors_scene, matches );

	double max_dist = 0; double min_dist = 100;

	//-- Quick calculation of max and min distances between keypoints
	for( int i = 0; i < descriptors_object.rows; i++ )
	{ double dist = matches[i].distance;
	if( dist < min_dist ) min_dist = dist;
	if( dist > max_dist ) max_dist = dist;
	}

	printf("-- Max dist : %f \n", max_dist );
	printf("-- Min dist : %f \n", min_dist );

	//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
	std::vector< DMatch > good_matches;

	for( int i = 0; i < descriptors_object.rows; i++ )
	{ if( matches[i].distance < 3*min_dist )
	{ good_matches.push_back( matches[i]); }
	}

	Mat img_matches;
	drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
		good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
		vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

	//-- Localize the object
	std::vector<Point2f> obj;
	std::vector<Point2f> scene;

	for( int i = 0; i < good_matches.size(); i++ )
	{
		//-- Get the keypoints from the good matches
		obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
		scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
	}

	Mat H = findHomography( obj, scene, CV_RANSAC );

	//-- Get the corners from the image_1 ( the object to be "detected" )
	std::vector<Point2f> obj_corners(4);
	obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
	obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
	std::vector<Point2f> scene_corners(4);

	perspectiveTransform( obj_corners, scene_corners, H);

	//-- Draw lines between the corners (the mapped object in the scene - image_2 )
	line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
	line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
	line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
	line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );

	//-- Show detected matches
	imshow( "Good Matches & Object detection", img_matches );

	waitKey(0);
	return 0;
}

void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }*/


#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

#define  NUMCORNERS 20

void GetPixelFromColorImg(IplImage* pImg, int xIdx, int yIdx, uchar& red, uchar& green, uchar& blue)
{
	uchar* ptr = (uchar*) ( pImg->imageData + yIdx * pImg->widthStep );

	blue = ptr[3*xIdx];//blue
	green = ptr[3*xIdx+1];//green
	red = ptr[3*xIdx+2];//red		
}

void GetPixelFromGrayImg(IplImage* pImg, int xIdx, int yIdx, uchar& gray)
{
	uchar* ptr = (uchar*) ( pImg->imageData + yIdx * pImg->widthStep );

	gray = ptr[xIdx];//blue		
}

void FillImageRegionWithSingleColor(IplImage* pImg, Rect& r, uchar red, uchar green, uchar blue, bool bColor)
{
	//modify the pixel regions
	for( int y=r.y; y<(r.y+r.height); y++ ) { 
		uchar* ptr = (uchar*) ( pImg->imageData + y * pImg->widthStep ); 
		for( int x=r.x; x<(r.x+r.width); x++ ) { 
			if(bColor)//3 channels
			{ ptr[3*x] = blue;ptr[3*x+1] = green;ptr[3*x+2] = red;} //Set red to max (BGR format)
			else
				ptr[x] = red;
		}
	}	
}
//copy the content from iplimage to mat
void CopyImageRegionToSingleChannelMat(IplImage* pImg, IplImage* mat, Rect& r, bool bColor)
{
	//modify the pixel regions
	for( int y=r.y; y<(r.y+r.height); y++ ) { 
		uchar* ptr = (uchar*) ( pImg->imageData + y * pImg->widthStep );
		uchar* ptrROI = (uchar*) ( mat->imageData + (y-r.y) * mat->widthStep );
		for( int x=r.x; x<(r.x+r.width); x++ ) { 
			if(bColor)//3 channels
				ptrROI[(x-r.x)] = ptr[3*x];//Set red to max (BGR format)
			else
				ptrROI[(x-r.x)] = ptr[x];
		}
	}	
}

/*int main()
{
	int i, corner_count = NUMCORNERS;
	IplImage *dst_img1, *dst_img2, *src_img_gray;
	IplImage *eig_img, *temp_img;
	CvPoint2D32f *corners;

	//image file
	char imagePath[256] = "CapTest2-00000-00003_s.jpg";
	printf("%s\n", imagePath);

	dst_img1 = cvLoadImage (imagePath, CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
	//modify the pixel regions
	FillImageRegionWithSingleColor(dst_img1, Rect(630, 375, (dst_img1->width-630), (dst_img1->height-375)), 241, 241, 241, true);
	FillImageRegionWithSingleColor(dst_img1, Rect(0, 0, 443, 1589), 241, 241, 241, true);
	FillImageRegionWithSingleColor(dst_img1, Rect(1699, 0, 686, 1589), 241, 241, 241, true);

	dst_img2 = cvCloneImage (dst_img1);
	src_img_gray = cvLoadImage (imagePath, CV_LOAD_IMAGE_GRAYSCALE);
	//modify the pixel regions
	FillImageRegionWithSingleColor(src_img_gray, Rect(630, 375, (dst_img1->width-630), (dst_img1->height-375)), 241, 241, 241, false);
	FillImageRegionWithSingleColor(src_img_gray, Rect(0, 0, 443, 1589), 241, 241, 241, false);
	FillImageRegionWithSingleColor(src_img_gray, Rect(1699, 0, 686, 1589), 241, 241, 241, false);

	eig_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
	temp_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
	corners = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f));

	// (1)Corner detection using cvCornerMinEigenVal
	cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &corner_count, 0.1, 15);
	cvFindCornerSubPix (src_img_gray, corners, corner_count,
		cvSize (3, 3), cvSize (-1, -1), cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03));
	// (2)Draw the detected corner
	for (i = 0; i < corner_count; i++)
		cvCircle (dst_img1, cvPointFrom32f (corners[i]), 3, CV_RGB (255, 0, 0), 2);

	//Message for debugging
	printf("MinEigenVal corner count = %d\n", corner_count);

	// (3)Corner detection using cvCornerHarris
	corner_count = NUMCORNERS;
	cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &corner_count, 0.1, 15, NULL, 3, 1, 0.1);
	cvFindCornerSubPix (src_img_gray, corners, corner_count,
		cvSize (3, 3), cvSize (-1, -1), cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03));
	// (4)Draw the detected corner
	for (i = 0; i < corner_count; i++)
		cvCircle (dst_img2, cvPointFrom32f (corners[i]), 3, CV_RGB (0, 0, 255), 2);

	//Message for debugging
	printf("Harris corner count = %d\n", corner_count);

	// (5)Display the result
	cvNamedWindow ("EigenVal", CV_WINDOW_AUTOSIZE);
	cvShowImage ("EigenVal", dst_img1);
	cvNamedWindow ("Harris", CV_WINDOW_AUTOSIZE);
	cvShowImage ("Harris", dst_img2);
	cvWaitKey (0);

	cvDestroyWindow ("EigenVal");
	cvDestroyWindow ("Harris");
	cvReleaseImage (&dst_img1);
	cvReleaseImage (&dst_img2);
	cvReleaseImage (&eig_img);
	cvReleaseImage (&temp_img);
	cvReleaseImage (&src_img_gray);

	return 0;
}*/

/*int main()
{
	int i, corner_count = NUMCORNERS;
	IplImage *dst_img1, *src_img_gray;
	IplImage *eig_img, *temp_img;
	CvPoint2D32f *corners;

	//image file
	//char imagePath[256] = "CapTest2-00000-00003.jpg";
	char imagePath[256] = "test1.jpg";
	printf("%s\n", imagePath);

	dst_img1 = cvLoadImage (imagePath, CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
	//modify the pixel regions
	uchar red = 0, green = 0, blue = 0;
	GetPixelFromColorImg(dst_img1, 1004, 890, red, green, blue);	

	Rect r1(1240, 735, 2618, 2442);
	Rect r2(0, 0, 883, 3177);
	Rect r3(3271, 0, 1499, 3177);

	FillImageRegionWithSingleColor(dst_img1, r1, red, green, blue, true);
	FillImageRegionWithSingleColor(dst_img1, r2, red, green, blue, true);
	FillImageRegionWithSingleColor(dst_img1, r3, red, green, blue, true);

	src_img_gray = cvLoadImage (imagePath, CV_LOAD_IMAGE_GRAYSCALE);
	//modify the pixel regions
	FillImageRegionWithSingleColor(src_img_gray, r1, red, green, blue, false);
	FillImageRegionWithSingleColor(src_img_gray, r2, red, green, blue, false);
	FillImageRegionWithSingleColor(src_img_gray, r3, red, green, blue, false);

	eig_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
	temp_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
	corners = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f));

	// (3)Corner detection using cvCornerHarris
	corner_count = NUMCORNERS;
	cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &corner_count, 0.1, 15, NULL, 3, 1, 0.04);
	//cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &corner_count, 0.1, 15);
	cvFindCornerSubPix (src_img_gray, corners, corner_count,
		cvSize (3, 3), cvSize (-1, -1), cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03));
	// (4)Draw the detected corner
	for (i = 0; i < corner_count; i++)
		cvCircle (dst_img1, cvPointFrom32f (corners[i]), 3, CV_RGB (0, 0, 255), 2);

	//Message for debugging
	printf("Harris corner count = %d\n", corner_count);

	// (5)Display the result
	cvNamedWindow ("Harris", CV_WINDOW_AUTOSIZE);
	cvShowImage ("Harris", dst_img1);
	cvWaitKey (0);

	cvSaveImage("harrisCorner.jpg",dst_img1);

	cvDestroyWindow ("Harris");
	cvReleaseImage (&dst_img1);
	cvReleaseImage (&eig_img);
	cvReleaseImage (&temp_img);
	cvReleaseImage (&src_img_gray);

	return 0;
}*/

#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

IplImage *img0,*selectedImg,*temp;
int iNeighborSize = 15;

struct ImgInfo
{
	IplImage* m_pImg;
	bool m_bColor;
	std::vector<CvPoint2D32f> m_arrCorners;

	ImgInfo():m_pImg(NULL),m_bColor(true)
	{}
};


void findCornersInSquare(ImgInfo* pImgInfo, int x, int y, int iNeighborSize)
{
	int iSquareSize = 2*iNeighborSize+1;
	Rect r(x-iNeighborSize,y-iNeighborSize,iSquareSize,iSquareSize);
	printf("rect:(%d,%d,%d,%d)\n",r.x,r.y,r.width,r.height);
	IplImage* LocalROI = cvCreateImage(cvSize(iSquareSize,iSquareSize),IPL_DEPTH_8U,1);
	//copy the content from iplimage to mat
	CopyImageRegionToSingleChannelMat(pImgInfo->m_pImg, LocalROI, r, pImgInfo->m_bColor);
	//DEBUG
	//cvSaveImage("LocalROI.jpg",LocalROI);
	//detect corner
	int corner_count = 1;
	IplImage* eig_img = cvCreateImage (cvGetSize (LocalROI), IPL_DEPTH_32F, 1);
	IplImage* temp_img = cvCreateImage (cvGetSize (LocalROI), IPL_DEPTH_32F, 1);
	CvPoint2D32f corner;

	// (1)Corner detection using cvCornerHarris
	cvGoodFeaturesToTrack (LocalROI, eig_img, temp_img, &corner, &corner_count, 0.1, 15, NULL, 3, 1, 0.04);
	// (2)cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &corner_count, 0.1, 15);
	cvFindCornerSubPix (LocalROI, &corner, corner_count,
		cvSize (3, 3), cvSize (-1, -1), cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03));
	// (3)shift the corner point
	CvPoint2D32f FinalCorner;
	FinalCorner.x = corner.x - iNeighborSize + x;
	FinalCorner.y = corner.y - iNeighborSize + y;
	pImgInfo->m_arrCorners.push_back(FinalCorner);
	printf("%f,%f\n",FinalCorner.x,FinalCorner.y);

	// (4)Draw the detected corner
#if 0
	cvCircle (LocalROI, cvPointFrom32f (corner), 3, CV_RGB (0, 0, 255));
	cvSaveImage("LocalROI.jpg",LocalROI);
#endif
	cvReleaseImage(&LocalROI);
}

void ShowTheCornerPoints(ImgInfo* pImgInfo)
{
	for(int i = 0; i < pImgInfo->m_arrCorners.size(); i++)
		cvCircle (pImgInfo->m_pImg, cvPointFrom32f (pImgInfo->m_arrCorners[i]), 13, CV_RGB (0, 0, 255),5);
}

void mouseHandler(int event, int x, int y, int flags, void *param)
{
	ImgInfo* pImgInfo = (ImgInfo*)(param);
	switch(event) {
	case CV_EVENT_LBUTTONDOWN:{		//left button press
		findCornersInSquare(pImgInfo, x, y, iNeighborSize);
	    }
		break;

	case CV_EVENT_LBUTTONUP:{	//left mouse button release
		ShowTheCornerPoints(pImgInfo);
		cvShowImage("Drag & Drop", pImgInfo->m_pImg);
		}
		break;
		
	}
}

//draw the scene components
/*void showImage(){
	IplImage *img2=img0;

	//draw the points
	for(int j=0;j<nop;j++){		
		img2 = cvCloneImage(img2);
		cvRectangle(img2, 
			cvPoint(globalCoordinateX[j] - 1, globalCoordinateY[j] - 1), 
			cvPoint(globalCoordinateX[j] + 1, globalCoordinateY[j] + 1), 
			cvScalar(255, 0,  0,0), 2, 8, 0);


		//draw the lines
		for(int k=j+1;k<nop;k++){
			img2 = cvCloneImage(img2);
			cvLine(img2,
				cvPoint(globalCoordinateX[j] , globalCoordinateY[j] ), 
				cvPoint(globalCoordinateX[k] , globalCoordinateY[k] ), 
				cvScalar(255, 0,  0,0), 1,8,0);
		}
	}
	cvShowImage("Drag & Drop", img2);
	cvReleaseImage(&img2);
}*/




int main(int argc, char** argv)
{
	//img0 = cvLoadImage("test1.jpg", CV_LOAD_IMAGE_COLOR);
	ImgInfo imgInfo;
	imgInfo.m_pImg = cvLoadImage("CapTest2-00000-00003_s_test.png", CV_LOAD_IMAGE_COLOR);
	//imgInfo.pImg = cvLoadImage("CapTest2-00001-00003_s_test.png", CV_LOAD_IMAGE_COLOR);
	imgInfo.m_bColor = true;	 
	//cvNamedWindow("Drag & Drop",CV_WINDOW_NORMAL | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
	cvNamedWindow("Drag & Drop",CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
	cvSetMouseCallback( "Drag & Drop", mouseHandler, (void*)(&imgInfo) );
	cvShowImage("Drag & Drop", imgInfo.m_pImg);
	//cvWaitKey(0);
	while(true)
	{
		char key = waitKey(0);

		if (key == 'p')
		{
			printf("start propagating the local regions!\n");
			ImgInfo imgInfo1;
			imgInfo1.m_pImg = cvLoadImage("CapTest2-00001-00003_s_test.png", CV_LOAD_IMAGE_COLOR);
			//imgInfo.pImg = cvLoadImage("CapTest2-00001-00003_s_test.png", CV_LOAD_IMAGE_COLOR);
			imgInfo1.m_bColor = true;
			//find the corners
			for (int i = 0; i < imgInfo.m_arrCorners.size(); i++)
			{
				findCornersInSquare(&imgInfo1,imgInfo.m_arrCorners[i].x,imgInfo.m_arrCorners[i].y,iNeighborSize);
			}
			ShowTheCornerPoints(&imgInfo1);
			cvNamedWindow("Propagated image 1",CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
			cvShowImage("Propagated image 1", imgInfo1.m_pImg);
		}
		else if (key == 27)//ascii code of 'esc'
			break;
	}

	cvDestroyWindow("Drag & Drop");
	cvSaveImage("Corners.jpg",imgInfo.m_pImg);
	cvReleaseImage(&imgInfo.m_pImg);	

	return 0;
}


